import tkinter as tk
from tkinter import ttk, filedialog, scrolledtext
import requests
import os
import subprocess
import threading
from tkinter import messagebox
import json
import winreg
import configparser
import re

VERSION = "1.0.0"  # 添加版本1常量

class PythonInstaller:
    def __init__(self):
        # 首先初始化基础变量
        self.default_download_dir = os.path.join(os.path.expanduser("~"), "Downloads")
        self.download_dir = self.default_download_dir

        # 初始化URL常量
        self.VSCODE_URL = "https://vscode.download.prss.microsoft.com/dbazure/download"
        self.GIT_URL = "https://github.com/git-for-windows/git/releases/latest"  # 使用latest链接
        self.PYTHON_API_URL = "https://www.python.org/downloads/"  # 使用主下载页
        self.VSCODE_VERSIONS_URL = "https://update.code.visualstudio.com/api/releases/stable"
        self.GIT_VERSIONS_URL = "https://api.github.com/repos/git-for-windows/git/releases/latest"  # 直接获取最新版
        self.GIT_MIRRORS = {
            "Github官方": "https://github.com/git-for-windows/git/releases/download/",
            "淘宝镜像": "https://registry.npmmirror.com/-/binary/git-for-windows/",
            "华为镜像": "https://repo.huaweicloud.com/git-for-windows/",
            "腾讯镜像": "https://mirrors.cloud.tencent.com/git-for-windows/"
        }
        self.current_git_mirror = "Github官方"

        # 初始化任务管理
        self.active_threads = []
        self.downloaded_files = {}

        # 初始化状态变量
        self.installing = False
        self.current_downloads = {}

        # 创建主窗口
        self.root = tk.Tk()
        self.root.title(f"DeepSeek软件开发环境安装管理器  v{VERSION}  公众号:传德源安全实验室  By:y4n6zh40")
        self.root.geometry("800x600")

        # 设置窗口图标和主题
        self.style = ttk.Style()
        self.style.configure('Custom.TLabelframe', padding=10)
        self.style.configure('Custom.TButton', padding=5)

        # 添加状态栏
        self.status_bar = ttk.Label(self.root, text=f"版本 {VERSION}", relief=tk.SUNKEN, anchor=tk.E)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

        # 创建并设置标签页
        self.tab_control = ttk.Notebook(self.root)
        self.readme_tab = ttk.Frame(self.tab_control)
        self.vscode_tab = ttk.Frame(self.tab_control)
        self.python_tab = ttk.Frame(self.tab_control)
        self.git_tab = ttk.Frame(self.tab_control)

        self.tab_control.add(self.readme_tab, text='使用说明')
        self.tab_control.add(self.vscode_tab, text='VSCode 安装')
        self.tab_control.add(self.python_tab, text='Python 安装')
        self.tab_control.add(self.git_tab, text='Git 安装')
        self.tab_control.pack(expand=1, fill="both")

        # 设置各个标签页
        self.setup_readme_tab()
        self.setup_vscode_tab()
        self.setup_python_tab()
        self.setup_git_tab()

        # 绑定窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

    def setup_readme_tab(self):
        # 创建可滚动文本区域
        text_area = scrolledtext.ScrolledText(
            self.readme_tab,
            wrap=tk.WORD,
            width=70,
            height=30
        )
        text_area.pack(expand=True, fill='both', padx=10, pady=10)

        # 读取并显示README内容
        try:
            with open('README.md', 'r', encoding='utf-8') as f:
                readme_content = f.read()
            text_area.insert(tk.END, readme_content)
            text_area.configure(state='disabled')  # 设置为只读
        except Exception as e:
            text_area.insert(tk.END, "无法加载说明文件，请确保README.md存在。")
            text_area.configure(state='disabled')

    def setup_python_tab(self):
        main_frame = ttk.Frame(self.python_tab)
        main_frame.pack(fill='both', expand=True, padx=20, pady=10)

        # 下载部分框架
        download_frame = ttk.LabelFrame(main_frame, text="下载 Python", style='Custom.TLabelframe')
        download_frame.pack(fill='x', pady=(0, 10))

        # 下载路径选择框架
        download_path_frame = ttk.Frame(download_frame)
        download_path_frame.pack(fill='x', pady=5)
        ttk.Label(download_path_frame, text="下载位置:").pack(side='left', padx=5)
        self.download_path = ttk.Entry(download_path_frame)
        self.download_path.pack(side='left', fill='x', expand=True, padx=5)
        self.download_path.insert(0, self.default_download_dir)
        browse_download_btn = ttk.Button(download_path_frame, text="浏览...",
                                       command=self.browse_download_path)
        browse_download_btn.pack(side='left', padx=5)

        # 版本选择框架
        version_frame = ttk.Frame(download_frame)
        version_frame.pack(fill='x', pady=5)
        ttk.Label(version_frame, text="选择版本:").pack(side='left', padx=5)
        self.version_var = tk.StringVar()
        self.version_combo = ttk.Combobox(version_frame, textvariable=self.version_var, width=30)
        self.version_combo['values'] = self.get_python_versions()
        self.version_combo.pack(side='left', padx=5)

        # 添加下载链接显示
        self.python_link_entry = ttk.Entry(version_frame, width=40, state='readonly')
        self.python_link_entry.pack(side='left', padx=5, fill='x', expand=True)

        # 绑定版本选择事件
        self.version_combo.bind('<<ComboboxSelected>>', self._on_python_version_selected)

        # 下载按钮和进度条框架
        download_controls = ttk.Frame(download_frame)
        download_controls.pack(fill='x', pady=5)

        btn_frame = ttk.Frame(download_controls)
        btn_frame.pack(fill='x')

        self.download_btn = ttk.Button(btn_frame, text="自动下载",
                                     command=self.download_python,
                                     style='Custom.TButton')
        self.download_btn.pack(side='left', padx=5)

        self.manual_download_btn = ttk.Button(btn_frame, text="获取下载链接",
                                            command=self.get_download_link,
                                            style='Custom.TButton')
        self.manual_download_btn.pack(side='left', padx=5)

        test_conn_btn = ttk.Button(btn_frame, text="测试连接",
                                 command=lambda: self.test_connection(self.PYTHON_API_URL, "Python"),
                                 style='Custom.TButton')
        test_conn_btn.pack(side='left', padx=5)

        self.download_progress = ttk.Progressbar(download_controls, length=400, mode='determinate')
        self.download_progress.pack(pady=5)

        # 安装部分框架
        install_frame = ttk.LabelFrame(main_frame, text="安装 Python", style='Custom.TLabelframe')
        install_frame.pack(fill='x', pady=(0, 10))

        # 安装路径框架
        path_frame = ttk.Frame(install_frame)
        path_frame.pack(fill='x', pady=5)
        ttk.Label(path_frame, text="安装路径:").pack(side='left', padx=5)
        self.install_path = ttk.Entry(path_frame)
        self.install_path.pack(side='left', fill='x', expand=True, padx=5)
        self.install_path.insert(0, "D:\\Program Files\\Python")
        browse_btn = ttk.Button(path_frame, text="浏览...", command=self.browse_python_path)
        browse_btn.pack(side='left', padx=5)

        # 环境变量选项
        self.add_path_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(install_frame, text="添加到环境变量", variable=self.add_path_var).pack(pady=5)

        # 安装按钮
        self.install_btn = ttk.Button(install_frame, text="安装Python",
                                    command=self.install_python,
                                    state='disabled',  # 初始状态禁用
                                    style='Custom.TButton')
        self.install_btn.pack(pady=10)

        # 安装状态标签
        self.status_label = ttk.Label(install_frame, text="", foreground="gray")
        self.status_label.pack(pady=5)

        # 在安装按钮旁添加手动安装按钮
        self.manual_python_install_btn = ttk.Button(install_frame, text="手动安装",
                                                command=self.manual_install_python,
                                                style='Custom.TButton')
        self.manual_python_install_btn.pack(pady=5)

    def setup_git_tab(self):
        main_frame = ttk.Frame(self.git_tab)
        main_frame.pack(fill='both', expand=True, padx=20, pady=5)

        # 上半部分框架
        top_frame = ttk.Frame(main_frame)
        top_frame.pack(fill='x', pady=2)

        # 下载和安装配置部分
        left_frame = ttk.Frame(top_frame)
        left_frame.pack(side='left', fill='both', expand=True, padx=(0,5))

        # ===== 下载部分 =====
        download_frame = ttk.LabelFrame(left_frame, text="Git 下载", style='Custom.TLabelframe')
        download_frame.pack(fill='x', pady=2)

        # 版本选择和下载链接
        version_frame = ttk.Frame(download_frame)
        version_frame.pack(fill='x', pady=2)
        ttk.Label(version_frame, text="版本:").pack(side='left', padx=2)
        self.git_version_var = tk.StringVar()
        self.git_version_combo = ttk.Combobox(version_frame, textvariable=self.git_version_var, width=15)
        self.git_version_combo['values'] = self.get_git_versions()
        self.git_version_combo.pack(side='left', padx=2)
        self.git_version_combo.bind('<<ComboboxSelected>>', self._on_git_version_selected)

        # 下载链接显示
        self.git_link_entry = ttk.Entry(version_frame, width=50, state='readonly')
        self.git_link_entry.pack(side='left', padx=2, fill='x', expand=True)

        # 下载路径选择框架
        download_path_frame = ttk.Frame(download_frame)
        download_path_frame.pack(fill='x', pady=2)
        ttk.Label(download_path_frame, text="下载位置:").pack(side='left', padx=2)
        self.git_download_path = ttk.Entry(download_path_frame)
        self.git_download_path.pack(side='left', fill='x', expand=True, padx=2)
        self.git_download_path.insert(0, self.default_download_dir)
        browse_git_download_btn = ttk.Button(download_path_frame, text="浏览...",
                                         command=self.browse_git_download_path)
        browse_git_download_btn.pack(side='right', padx=2)

        # 添加镜像选择框架
        mirror_frame = ttk.Frame(download_frame)
        mirror_frame.pack(fill='x', pady=2)
        ttk.Label(mirror_frame, text="下载源:").pack(side='left', padx=2)
        self.git_mirror_var = tk.StringVar(value=self.current_git_mirror)
        self.git_mirror_combo = ttk.Combobox(mirror_frame, textvariable=self.git_mirror_var,
                                           values=list(self.GIT_MIRRORS.keys()), width=15)
        self.git_mirror_combo.pack(side='left', padx=2)
        self.git_mirror_combo.bind('<<ComboboxSelected>>', self._on_git_mirror_selected)

        # 下载按钮组
        btn_frame = ttk.Frame(download_frame)
        btn_frame.pack(fill='x', pady=2)

        self.git_download_btn = ttk.Button(btn_frame, text="下载Git", command=self.download_git)
        self.git_download_btn.pack(side='left', padx=2)

        test_conn_btn = ttk.Button(btn_frame, text="测试连接",
                                command=lambda: self.test_connection(self.GIT_URL, "Git"))
        test_conn_btn.pack(side='left', padx=2)

        self.git_download_progress = ttk.Progressbar(download_frame, length=400, mode='determinate')
        self.git_download_progress.pack(fill='x', pady=2)

        # ===== 安装部分 =====
        install_frame = ttk.LabelFrame(left_frame, text="Git 安装", style='Custom.TLabelframe')
        install_frame.pack(fill='x', pady=2)

        path_frame = ttk.Frame(install_frame)
        path_frame.pack(fill='x', pady=2)
        ttk.Label(path_frame, text="安装路径:").pack(side='left', padx=2)
        self.git_install_path = ttk.Entry(path_frame)
        self.git_install_path.pack(side='left', fill='x', expand=True, padx=2)
        self.git_install_path.insert(0, "D:\\Program Files\\Git")

        browse_git_btn = ttk.Button(path_frame, text="浏览...", command=self.browse_git_path)
        browse_git_btn.pack(side='right', padx=2)

        self.install_git_btn = ttk.Button(install_frame, text="安装Git",
                                        command=self.install_git,
                                        state='disabled')
        self.install_git_btn.pack(pady=2)

        self.git_install_progress = ttk.Progressbar(install_frame, length=400, mode='determinate')
        self.git_install_progress.pack(fill='x', pady=2)

        # 在安装框架中添加手动安装按钮
        self.manual_git_install_btn = ttk.Button(install_frame, text="手动安装",
                                             command=self.manual_install_git,
                                             style='Custom.TButton')
        self.manual_git_install_btn.pack(pady=2)

        # ===== Git配置部分 =====
        right_frame = ttk.Frame(top_frame)
        right_frame.pack(side='right', fill='both', expand=True)

        # 用户配置
        config_frame = ttk.LabelFrame(right_frame, text="Git 用户配置", style='Custom.TLabelframe')
        config_frame.pack(fill='x', pady=2)

        grid_frame = ttk.Frame(config_frame)
        grid_frame.pack(fill='x', pady=2)

        ttk.Label(grid_frame, text="用户名:").grid(row=0, column=0, padx=2, pady=2)
        self.git_username = ttk.Entry(grid_frame)
        self.git_username.grid(row=0, column=1, padx=2, pady=2, sticky='ew')

        ttk.Label(grid_frame, text="邮箱:").grid(row=1, column=0, padx=2, pady=2)
        self.git_email = ttk.Entry(grid_frame)
        self.git_email.grid(row=1, column=1, padx=2, pady=2, sticky='ew')

        # 仓库配置
        repo_frame = ttk.LabelFrame(right_frame, text="仓库配置", style='Custom.TLabelframe')
        repo_frame.pack(fill='x', pady=2)

        # 仓库地址框架
        repo_addr_frame = ttk.Frame(repo_frame)
        repo_addr_frame.pack(fill='x', pady=2)
        ttk.Label(repo_addr_frame, text="远程仓库地址:").pack(side='left', padx=2)
        self.git_repo = ttk.Entry(repo_addr_frame)
        self.git_repo.pack(side='left', fill='x', expand=True, padx=2)

        # Git认证框架
        auth_frame = ttk.Frame(repo_frame)
        auth_frame.pack(fill='x', pady=2)
        
        # 初始化用户名和密码输入框
        ttk.Label(auth_frame, text="用户名:").pack(side='left', padx=2)
        self.repo_username = ttk.Entry(auth_frame, width=20)
        self.repo_username.pack(side='left', padx=2)
        
        ttk.Label(auth_frame, text="密码:").pack(side='left', padx=2)
        self.repo_password = ttk.Entry(auth_frame, show="*", width=20)
        self.repo_password.pack(side='left', padx=2)

        btn_frame = ttk.Frame(repo_frame)
        btn_frame.pack(fill='x', pady=2)
        ttk.Button(btn_frame, text="测试连接", command=self.test_repo_connection).pack(side='left', padx=2)
        ttk.Button(btn_frame, text="保存配置", command=self.save_repo_config).pack(side='left', padx=2)

    def validate_email(self, email):
        """验证邮箱格式"""
        if not email:
            return False, "邮箱地址不能为空"

        if '@' not in email:
            return False, "邮箱地址必须包含@符号"

        if len(email) > 254:
            return False, "邮箱地址长度不能超过254个字符"

        # 更严格的邮箱格式验证规则
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        if not re.match(pattern, email):
            return False, "邮箱格式不正确，正确格式例如：username@domain.com"

        # 检查用户名部分
        local_part = email.split('@')[0]
        if len(local_part) > 64:
            return False, "邮箱用户名部分不能超过64个字符"

        return True, "邮箱格式正确"

    def save_git_config(self):
        try:
            username = self.git_username.get().strip()
            email = self.git_email.get().strip()
            password = self.git_password.get().strip()

            if not username:
                messagebox.showwarning("警告", "用户名不能为空！")
                self.git_username.focus()  # 聚焦到用户名输入框
                return

            # 验证邮箱
            is_valid, message = self.validate_email(email)
            if not is_valid:
                messagebox.showwarning("警告", message)
                self.git_email.focus()  # 聚焦到邮箱输入框
                self.git_email.select_range(0, tk.END)  # 选中全部文本以便重新输入
                return

            # 设置全局配置
            subprocess.run(['git', 'config', '--global', 'user.name', username])
            subprocess.run(['git', 'config', '--global', 'user.email', email])

            if password:
                # 使用git credential store保存密码
                subprocess.run(['git', 'config', '--global', 'credential.helper', 'store'])
                # 在实际应用中应该使用更安全的凭证管理方式

            messagebox.showinfo("成功", "Git用户配置已保存！")

            # 更新状态栏显示配置信息
            self.status_bar.config(text=f"当前Git用户: {username} ({email})")

        except Exception as e:
            messagebox.showerror("错误", f"保存Git配置失败: {str(e)}")

    def save_git_advanced_config(self):
        try:
            proxy = self.git_proxy.get().strip()
            branch = self.default_branch.get().strip()

            if proxy:
                # 设置代理
                subprocess.run(['git', 'config', '--global', 'http.proxy', proxy])
                subprocess.run(['git', 'config', '--global', 'https.proxy', proxy])
            else:
                # 清除代理
                subprocess.run(['git', 'config', '--global', '--unset', 'http.proxy'])
                subprocess.run(['git', 'config', '--global', '--unset', 'https.proxy'])

            if branch:
                # 设置默认分支名
                subprocess.run(['git', 'config', '--global', 'init.defaultBranch', branch])

            messagebox.showinfo("成功", "Git高级配置已保存！")
        except Exception as e:
            messagebox.showerror("错误", f"保存Git高级配置失败: {str(e)}")

    def test_git_connection(self):
        try:
            username = self.git_username.get().strip()
            password = self.git_password.get().strip()

            if not username or not password:
                messagebox.showwarning("警告", "请输入用户名和密码！")
                return

            # 测试Git连接（这里以github为例）
            result = subprocess.run(
                ['git', 'ls-remote', 'https://github.com'],
                capture_output=True,
                text=True,
                env={'GIT_ASKPASS': 'echo', 'GIT_USERNAME': username, 'GIT_PASSWORD': password}
            )

            if result.returncode == 0:
                messagebox.showinfo("成功", "Git连接测试成功！")
            else:
                messagebox.showerror("错误", "Git连接测试失败，请检查凭证！")
        except Exception as e:
            messagebox.showerror("错误", f"连接测试失败: {str(e)}")

    def load_git_config(self):
        try:
            # 加载用户名
            result = subprocess.run(['git', 'config', '--global', 'user.name'],
                                 capture_output=True, text=True)
            if result.stdout:
                self.git_username.delete(0, tk.END)
                self.git_username.insert(0, result.stdout.strip())

            # 加载邮箱
            result = subprocess.run(['git', 'config', '--global', 'user.email'],
                                 capture_output=True, text=True)
            if result.stdout:
                self.git_email.delete(0, tk.END)
                self.git_email.insert(0, result.stdout.strip())

            # 加载代理设置
            result = subprocess.run(['git', 'config', '--global', 'http.proxy'],
                                 capture_output=True, text=True)
            if result.stdout:
                self.git_proxy.delete(0, tk.END)
                self.git_proxy.insert(0, result.stdout.strip())

            # 加载默认分支设置
            result = subprocess.run(['git', 'config', '--global', 'init.defaultBranch'],
                                 capture_output=True, text=True)
            if result.stdout:
                self.default_branch.delete(0, tk.END)
                self.default_branch.insert(0, result.stdout.strip())

            # 尝试加载保存的密码（如果有）
            try:
                with open(os.path.expanduser('~/.git-credentials'), 'r') as f:
                    credentials = f.read().strip()
                    if credentials:
                        # 从凭证中提取密码（示例格式：https://user:pass@github.com）
                        match = re.search(r'://[^:]+:([^@]+)@', credentials)
                        if (match):
                            self.git_password.delete(0, tk.END)
                            self.git_password.insert(0, match.group(1))
            except:
                pass  # 如果无法读取凭证文件，忽略错误

        except Exception:
            pass  # 忽略加载配置时的错误

    def setup_vscode_tab(self):
        main_frame = ttk.Frame(self.vscode_tab)
        main_frame.pack(fill='both', expand=True, padx=20, pady=10)

        # 下载部分框架
        download_frame = ttk.LabelFrame(main_frame, text="下载 VSCode", style='Custom.TLabelframe')
        download_frame.pack(fill='x', pady=(0, 10))

        # 版本和连接测试框架
        version_frame = ttk.Frame(download_frame)
        version_frame.pack(fill='x', pady=5)

        # 左侧版本选择
        version_left_frame = ttk.Frame(version_frame)
        version_left_frame.pack(side='left', fill='x', expand=True)
        ttk.Label(version_left_frame, text="选择版本:").pack(side='left', padx=5)
        self.vscode_version_var = tk.StringVar()
        self.vscode_version_combo = ttk.Combobox(version_left_frame, textvariable=self.vscode_version_var, width=30)
        self.vscode_version_combo['values'] = self.get_vscode_versions()
        self.vscode_version_combo.pack(side='left', padx=5)

        # 右侧连接测试
        test_conn_btn = ttk.Button(version_frame, text="测试下载连接",
                                command=lambda: self.test_connection(self.VSCODE_URL, "VSCode"),
                                style='Custom.TButton')
        test_conn_btn.pack(side='right', padx=5)

        # 下载路径选择框架
        download_path_frame = ttk.Frame(download_frame)
        download_path_frame.pack(fill='x', pady=5)
        ttk.Label(download_path_frame, text="下载位置:").pack(side='left', padx=5)
        self.vscode_download_path = ttk.Entry(download_path_frame)
        self.vscode_download_path.pack(side='left', fill='x', expand=True, padx=5)
        self.vscode_download_path.insert(0, self.default_download_dir)
        browse_download_btn = ttk.Button(download_path_frame, text="浏览...",
                                       command=self.browse_vscode_download_path)
        browse_download_btn.pack(side='left', padx=5)

        # 下载按钮框架
        btn_frame = ttk.Frame(download_frame)
        btn_frame.pack(fill='x', pady=5)

        # 按钮放在一行，使用左对齐
        btn_container = ttk.Frame(btn_frame)
        btn_container.pack(side='left')

        self.vscode_download_btn = ttk.Button(btn_container, text="自动下载",
                                          command=self.download_vscode,
                                          style='Custom.TButton')
        self.vscode_download_btn.pack(side='left', padx=5)

        self.vscode_manual_download_btn = ttk.Button(btn_container, text="获取下载链接",
                                                 command=self.get_vscode_download_link,
                                                 style='Custom.TButton')
        self.vscode_manual_download_btn.pack(side='left', padx=5)

        # 下载链接显示框架
        link_frame = ttk.Frame(download_frame)
        link_frame.pack(fill='x', pady=5)
        self.vscode_link_entry = ttk.Entry(link_frame, width=70, state='readonly')
        self.vscode_link_entry.pack(side='left', padx=5)

        # 下载进度条
        self.vscode_download_progress = ttk.Progressbar(download_frame, length=400, mode='determinate')
        self.vscode_download_progress.pack(pady=5)

        # 安装部分框架
        install_frame = ttk.LabelFrame(main_frame, text="安装 VSCode", style='Custom.TLabelframe')
        install_frame.pack(fill='x', pady=(0, 10))

        # 安装路径框架
        install_path_frame = ttk.Frame(install_frame)
        install_path_frame.pack(fill='x', pady=5)
        ttk.Label(install_path_frame, text="安装路径:").pack(side='left', padx=5)
        self.vscode_install_path = ttk.Entry(install_path_frame)
        self.vscode_install_path.pack(side='left', fill='x', expand=True, padx=5)
        self.vscode_install_path.insert(0, "D:\\Program Files\\Microsoft VS Code")
        browse_install_btn = ttk.Button(install_path_frame, text="浏览...",
                                    command=self.browse_vscode_path)
        browse_install_btn.pack(side='left', padx=5)

        # 安装选项框架
        options_frame = ttk.Frame(install_frame)
        options_frame.pack(fill='x', pady=5)

        # 用户级安装选项
        self.vscode_user_install = tk.BooleanVar(value=True)
        ttk.Checkbutton(options_frame, text="为当前用户安装",
                       variable=self.vscode_user_install).pack(side='left', padx=5)

        # 安装按钮
        self.vscode_install_btn = ttk.Button(install_frame, text="安装VSCode",
                                         command=self.install_vscode,
                                         state='disabled',
                                         style='Custom.TButton')
        self.vscode_install_btn.pack(pady=10)

        # 安装进度条
        self.vscode_install_progress = ttk.Progressbar(install_frame, length=400,
                                                   mode='determinate')
        self.vscode_install_progress.pack(pady=5)

        # 版本选择事件绑定
        self.vscode_version_combo.bind('<<ComboboxSelected>>', self._on_version_selected)

        # 在下载按钮框架中添加手动安装按钮
        self.manual_install_btn = ttk.Button(install_frame, text="手动安装",
                                         command=self.manual_install_vscode,
                                         style='Custom.TButton')
        self.manual_install_btn.pack(pady=5)

    def get_python_versions(self):
        """获取Python稳定版本列表"""
        try:
            response = requests.get("https://www.python.org/api/v2/downloads/release/")
            data = response.json()
            # 只获取正式发布版本，过滤掉alpha/beta/rc版本
            versions = [item['version'] for item in data['releases']
                      if not any(x in item['version'].lower() for x in ['a', 'b', 'rc'])]
            # 按版本号排序，最新版本在前
            versions.sort(reverse=True)
            return versions[:10]  # 返回最新的10个稳定版本
        except:
            return ["3.12.1", "3.11.7", "3.10.11"]  # 默认返回最新的稳定版本

    def get_vscode_versions(self):
        """获取VSCode版本列表"""
        try:
            # 获取最新版本和commit信息
            response = requests.get("https://update.code.visualstudio.com/api/commits/stable/win32-x64", timeout=5)
            data = response.json()
            
            versions = []
            self.vscode_commits = {}
            
            # 添加当前最新版本
            latest_version = data.get('productVersion', '')
            latest_commit = data.get('version', '')
            if latest_version and latest_commit:
                versions.append(latest_version)
                self.vscode_commits[latest_version] = latest_commit
            
            # 获取历史版本列表
            history_response = requests.get(self.VSCODE_VERSIONS_URL, timeout=5)
            history_data = history_response.json()
            
            # 添加历史版本
            for release in history_data:
                version = release['productVersion']
                commit = release.get('version', '')
                if version not in versions:
                    versions.append(version)
                    self.vscode_commits[version] = commit
            
            return versions[:15]  # 返回最新的15个版本
        except Exception as e:
            print(f"获取VSCode版本失败: {e}")
            return ["1.85.1", "1.85.0", "1.84.2"]  # 默认版本列表

    def get_git_versions(self):
        """获取Git最新版本"""
        try:
            # 先获取最新版
            latest_response = requests.get(self.GIT_VERSIONS_URL, timeout=5)
            latest_data = latest_response.json()
            latest_version = latest_data['tag_name'].replace('v', '')
            
            # 再获取其他版本
            all_versions_response = requests.get("https://api.github.com/repos/git-for-windows/git/releases")
            all_versions_data = all_versions_response.json()
            
            versions = [
                release['tag_name'].replace('v', '')
                for release in all_versions_data
                if not release['prerelease']
            ]
            
            # 确保最新版在列表开头
            if latest_version in versions:
                versions.remove(latest_version)
            versions.insert(0, latest_version)
            
            return versions[:10]  # 返回最新的10个版本
        except:
            return ["2.43.0", "2.42.0", "2.41.0"]  # 默认返回最新的稳定版本

    def _manage_thread(self, thread, name):
        """管理线程"""
        self.active_threads.append((thread, name))
        thread.daemon = True  # 设置为守护线程
        thread.start()

    def download_python(self):
        """只处理下载功能"""
        if not self.version_var.get():
            messagebox.showwarning("警告", "请先选择Python版本！")
            return

        self.download_btn.configure(state='disabled')
        self.install_btn.configure(state='disabled')
        self.status_label.config(text="正在下载...", foreground="blue")

        version = self.version_var.get()
        thread = threading.Thread(target=self._download_python_thread, args=(version,))
        self._manage_thread(thread, "Python下载")

    def _download_file(self, url, save_path, progress_bar, callback=None):
        """通用文件下载函数"""
        try:
            response = requests.get(url, stream=True)
            response.raise_for_status()  # 检查下载状态
            total_size = int(response.headers.get('content-length', 0))
            
            if total_size == 0:
                raise Exception("无法获取文件大小，下载可能不完整")

            downloaded_size = 0
            with open(save_path, 'wb') as f:
                for chunk in response.iter_content(chunk_size=8192):
                    if chunk:
                        f.write(chunk)
                        downloaded_size += len(chunk)
                        progress = (downloaded_size / total_size) * 100
                        progress_bar['value'] = progress
                        self.root.update_idletasks()

            if os.path.getsize(save_path) == 0:
                raise Exception("下载文件为空")

            if callback:
                callback(save_path)
            return save_path
        except Exception as e:
            if os.path.exists(save_path):
                os.remove(save_path)
            raise e

    def _on_download_complete(self, software_type, filepath):
        """下载完成后的回调处理"""
        self.downloaded_files[software_type] = filepath
        if software_type == 'python':
            self.install_btn.configure(state='normal')
        elif software_type == 'git':
            self.install_git_btn.configure(state='normal')
        elif software_type == 'vscode':
            self.vscode_install_btn.configure(state='normal')

    def _download_python_thread(self, version):
        try:
            url = f"https://www.python.org/ftp/python/{version}/python-{version}-amd64.exe"
            filename = os.path.join(self.download_path.get(), f"python-{version}-amd64.exe")
            
            self.status_label.config(text="正在下载...", foreground="blue")
            self._download_file(
                url, 
                filename, 
                self.download_progress,
                lambda fp: self._on_download_complete('python', fp)
            )
            
            self.status_label.config(text=f"下载完成: {filename}", foreground="green")
            messagebox.showinfo("成功", f"Python下载完成！\n保存位置：{filename}")
            
        except Exception as e:
            self.status_label.config(text="下载失败", foreground="red")
            messagebox.showerror("错误", f"下载失败: {str(e)}")
        finally:
            self.download_btn.configure(state='normal')
            self.download_progress['value'] = 0
            self.active_threads = [(t, n) for t, n in self.active_threads 
                                 if t.ident != threading.current_thread().ident]

    def get_download_link(self):
        """获取下载链接"""
        version = self.version_var.get()
        if not version:
            messagebox.showwarning("警告", "请先选择Python版本！")
            return

        url = f"https://www.python.org/ftp/python/{version}/python-{version}-amd64.exe"

        # 创建下载信息窗口
        info_window = tk.Toplevel(self.root)
        info_window.title("下载链接")
        info_window.geometry("500x150")

        # 添加链接显示
        link_frame = ttk.Frame(info_window)
        link_frame.pack(fill='x', padx=10, pady=5)

        link_entry = ttk.Entry(link_frame, width=70)
        link_entry.insert(0, url)
        link_entry.configure(state='readonly')
        link_entry.pack(side='left', padx=5)

        def copy_link():
            info_window.clipboard_clear()
            info_window.clipboard_append(url)
            copy_btn.configure(text="已复制！")
            info_window.after(1500, lambda: copy_btn.configure(text="复制链接"))

        copy_btn = ttk.Button(link_frame, text="复制链接", command=copy_link)
        copy_btn.pack(side='left', padx=5)

        # 修复引号问题的说明文本
        help_text = ("1. 复制链接后可使用浏览器或下载工具手动下载\n"
                    "2. 下载完成后请将文件移动到上方指定的下载位置\n"
                    "3. 文件下载完成后即可点击'安装Python'按钮进行安装")

        ttk.Label(info_window, text=help_text, justify='left').pack(pady=10)

    def install_python(self):
        """处理安装功能"""
        if 'python' not in self.downloaded_files:
            messagebox.showwarning("警告", "请先下载Python安装包！")
            return

        self.install_btn.configure(state='disabled')
        self.status_label.config(text="正在安装...", foreground="blue")

        thread = threading.Thread(target=self._install_python_thread)
        self._manage_thread(thread, "Python安装")

    def _install_python_thread(self):
        try:
            if self.installing:
                return
            self.installing = True
            
            filename = self.downloaded_files.get('python')
            if not filename or not os.path.exists(filename):
                raise Exception("安装文件不存在，请重新下载")
                
            install_path = self.install_path.get()
            if not install_path:
                raise Exception("请指定安装路径")

            if not os.path.exists(install_path):
                os.makedirs(install_path)

            self.status_label.config(text="正在安装...", foreground="blue")
            
            # 添加安装参数
            cmd = [
                filename,
                '/quiet',
                'InstallAllUsers=1',
                f'TargetDir="{install_path}"',
                'PrependPath=1' if self.add_path_var.get() else 'PrependPath=0'
            ]
            
            result = subprocess.run(cmd, capture_output=True, text=True)
            if result.returncode != 0:
                raise Exception(f"安装失败: {result.stderr}")

            if self.add_path_var.get():
                self.set_environment_variable(install_path)

            self.status_label.config(text="安装完成", foreground="green")
            messagebox.showinfo("成功", "Python安装完成！")
            
        except Exception as e:
            self.status_label.config(text="安装失败", foreground="red")
            messagebox.showerror("错误", f"安装失败: {str(e)}")
        finally:
            self.installing = False
            self.install_btn.configure(state='normal')
            self.active_threads = [(t, n) for t, n in self.active_threads 
                                 if t.ident != threading.current_thread().ident]

    def install_git(self):
        thread = threading.Thread(target=self._install_git_thread)
        self._manage_thread(thread, "Git安装")

    def _install_git_thread(self):
        try:
            self.install_git_btn.configure(state='disabled')
            version = self.git_version_var.get()
            if not version:
                messagebox.showwarning("警告", "请先选择Git版本！")
                return

            # 下载Git
            url = f"https://github.com/git-for-windows/git/releases/download/v{version}/Git-{version}-64-bit.exe"
            response = requests.get(url, stream=True)

            # 使用选择的下载路径
            filename = os.path.join(self.download_dir, "git-installer.exe")
            total_size = int(response.headers.get('content-length', 0))

            with open(filename, 'wb') as f:
                for data in response.iter_content(chunk_size=4096):
                    f.write(data)
                    self.git_progress['value'] = (f.tell() / total_size) * 100
                    self.root.update_idletasks()

            # 安装Git
            install_path = self.git_install_path.get()
            cmd = f'{filename} /SILENT /COMPONENTS="icons,ext\reg\shellhere,assoc,assoc_sh" /DIR="{install_path}"'
            subprocess.run(cmd, shell=True)

            # 安装完成后自动加载已有配置
            self.load_git_config()

            messagebox.showinfo("成功", "Git 安装完成！")
        except Exception as e:
            messagebox.showerror("错误", f"Git安装失败: {str(e)}")
        finally:
            self.install_git_btn.configure(state='normal')
            self.active_threads = [(t, n) for t, n in self.active_threads
                                 if t.ident != threading.current_thread().ident]

    def browse_python_path(self):
        path = filedialog.askdirectory(title="选择Python安装路径")
        if path:
            self.install_path.delete(0, tk.END)
            self.install_path.insert(0, path.replace('/', '\\'))

    def browse_git_path(self):
        path = filedialog.askdirectory(title="选择Git安装路径")
        if path:
            self.git_install_path.delete(0, tk.END)
            self.git_install_path.insert(0, path.replace('/', '\\'))

    def browse_vscode_path(self):
        path = filedialog.askdirectory(title="选择VSCode安装路径")
        if path:
            self.vscode_install_path.delete(0, tk.END)
            self.vscode_install_path.insert(0, path.replace('/', '\\'))

    def browse_vscode_download_path(self):
        """选择VSCode下载路径"""
        path = filedialog.askdirectory(title="选择VSCode下载位置")
        if path:
            self.vscode_download_path.delete(0, tk.END)
            self.vscode_download_path.insert(0, path)

    def install_vscode(self):
        thread = threading.Thread(target=self._install_vscode_thread)
        self._manage_thread(thread, "VSCode安装")

    def _install_vscode_thread(self):
        try:
            if 'vscode' not in self.downloaded_files:
                messagebox.showwarning("警告", "请先下载VSCode安装包！")
                return

            filename = self.downloaded_files['vscode']
            install_path = self.vscode_install_path.get()
            user_install = "/CURRENTUSER" if self.vscode_user_install.get() else "/ALLUSERS"

            cmd = f'{filename} {user_install} /SILENT /DIR="{install_path}"'
            subprocess.run(cmd, shell=True)

            messagebox.showinfo("成功", "VSCode 安装完成！")
        except Exception as e:
            messagebox.showerror("错误", f"VSCode安装失败: {str(e)}")
        finally:
            self.vscode_install_btn.configure(state='normal')
            self.vscode_install_progress['value'] = 0
            self.active_threads = [(t, n) for t, n in self.active_threads
                                 if t.ident != threading.current_thread().ident]

    def download_vscode(self):
        """处理VSCode下载"""
        version = self.vscode_version_var.get()
        if not version:
            messagebox.showwarning("警告", "请先选择VSCode版本！")
            return

        self.vscode_download_btn.configure(state='disabled')
        self.vscode_install_btn.configure(state='disabled')  # 修改这里，使用正确的变量名
        thread = threading.Thread(target=self._download_vscode_thread)
        self._manage_thread(thread, "VSCode下载")

    def _download_vscode_thread(self):
        try:
            version = self.vscode_version_var.get()
            commit = self.vscode_commits.get(version, '')
            
            if not commit:
                # 如果获取不到commit，使用备用下载链接
                url = f"https://update.code.visualstudio.com/{version}/win32-x64/stable"
            else:
                url = (f"https://vscode.download.prss.microsoft.com/dbazure/download/stable/"
                      f"{commit}/VSCodeUserSetup-x64-{version}.exe")
            
            response = requests.get(url, stream=True)

            filename = os.path.join(self.vscode_download_path.get(), "vscode-installer.exe")
            total_size = int(response.headers.get('content-length', 0))

            with open(filename, 'wb') as f:
                for data in response.iter_content(chunk_size=4096):
                    f.write(data)
                    self.vscode_download_progress['value'] = (f.tell() / total_size) * 100
                    self.root.update_idletasks()

            self.downloaded_files['vscode'] = filename
            messagebox.showinfo("成功", f"VSCode下载完成！\n保存位置：{filename}")
            self.vscode_install_btn.configure(state='normal')

        except Exception as e:
            messagebox.showerror("错误", f"VSCode下载失败: {str(e)}")
        finally:
            self.vscode_download_btn.configure(state='normal')
            self.vscode_download_progress['value'] = 0
            self.active_threads = [(t, n) for t, n in self.active_threads
                                 if t.ident != threading.current_thread().ident]

    def get_vscode_download_link(self):
        """获取VSCode下载链接"""
        version = self.vscode_version_var.get()
        if not version:
            messagebox.showwarning("警告", "请先选择VSCode版本！")
            return
            
        try:
            # 获取多个下载链接选项
            download_links = {
                "系统安装版(推荐)": f"https://vscode.download.prss.microsoft.com/dbazure/download/stable/system/VSCodeSetup-x64-{version}.exe",
                "用户安装版": f"https://vscode.download.prss.microsoft.com/dbazure/download/stable/user/VSCodeUserSetup-x64-{version}.exe",
                "ZIP免安装版": f"https://vscode.download.prss.microsoft.com/dbazure/download/stable/portable/VSCode-win32-x64-{version}.zip",
                "备用下载1": f"https://update.code.visualstudio.com/{version}/win32-x64/stable",
                "备用下载2": f"https://az764295.vo.msecnd.net/stable/latest/VSCodeSetup-x64-{version}.exe"
            }

            # 创建下载信息窗口
            info_window = tk.Toplevel(self.root)
            info_window.title("VSCode下载链接")
            info_window.geometry("800x400")
            
            # 创建说明文本
            help_text = ("请选择合适的下载链接：\n"
                        "1. 系统安装版：安装到系统目录，所有用户可用\n"
                        "2. 用户安装版：安装到用户目录，仅当前用户可用\n"
                        "3. ZIP免安装版：解压即可使用，适合便携使用\n"
                        "4. 如果上述链接无法下载，请尝试使用备用下载链接\n\n"
                        "下载完成后：\n"
                        "1. 将下载的文件移动到上方指定的下载位置\n"
                        "2. 点击'安装VSCode'按钮进行安装")
                        
            ttk.Label(info_window, text=help_text, justify='left').pack(pady=10, padx=10)

            # 创建链接列表框架
            links_frame = ttk.LabelFrame(info_window, text="下载链接")
            links_frame.pack(fill='x', padx=10, pady=5)
            
            for name, url in download_links.items():
                link_frame = ttk.Frame(links_frame)
                link_frame.pack(fill='x', pady=2)
                
                ttk.Label(link_frame, text=f"{name}:").pack(side='left', padx=5)
                link_entry = ttk.Entry(link_frame, width=80)
                link_entry.insert(0, url)
                link_entry.configure(state='readonly')
                link_entry.pack(side='left', padx=5, fill='x', expand=True)
                
                copy_btn = ttk.Button(link_frame, text="复制链接", 
                                    command=lambda u=url: self._copy_to_clipboard(info_window, u))
                copy_btn.pack(side='left', padx=5)

        except Exception as e:
            messagebox.showerror("错误", f"获取下载链接失败: {str(e)}")

    def _copy_to_clipboard(self, window, text):
        """复制文本到剪贴板"""
        window.clipboard_clear()
        window.clipboard_append(text)
        messagebox.showinfo("成功", "链接已复制到剪贴板！")

    def set_environment_variable(self, python_path):
        """改进的环境变量设置"""
        try:
            key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 
                               r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", 
                               0, winreg.KEY_ALL_ACCESS)
            
            current_path = winreg.QueryValueEx(key, "Path")[0]
            paths = current_path.split(';')
            
            # 清理旧的Python路径
            paths = [p for p in paths if 'python' not in p.lower()]
            
            # 添加新路径
            new_paths = [
                python_path,
                os.path.join(python_path, 'Scripts'),
                os.path.join(python_path, 'Lib', 'site-packages')
            ]
            
            paths.extend(new_paths)
            new_path = ';'.join(filter(None, paths))
            
            winreg.SetValueEx(key, "Path", 0, winreg.REG_EXPAND_SZ, new_path)
            winreg.CloseKey(key)
            
            # 广播环境变量更改消息
            subprocess.run(['setx', 'PYTHONPATH', python_path])
            os.environ['PYTHONPATH'] = python_path
            os.environ['Path'] = new_path
            
        except Exception as e:
            messagebox.showerror("错误", f"设置环境变量失败: {str(e)}")

    def test_connection(self, url, name):
        """测试URL连接"""
        try:
            if name == "VSCode":
                # VSCode特殊处理
                response = requests.get(url, timeout=5, allow_redirects=True)
                if response.status_code == 200:
                    messagebox.showinfo("成功", "VSCode官网连接正常！")
                else:
                    messagebox.showwarning("警告", f"VSCode官网连接可能存在问题，HTTP状态码: {response.status_code}")
            else:
                # 其他下载地址检测
                response = requests.head(url, timeout=5)
                if response.status_code == 200:
                    messagebox.showinfo("成功", f"{name}下载地址连接正常！")
                else:
                    messagebox.showwarning("警告", f"{name}下载地址可能存在问题，HTTP状态码: {response.status_code}")
        except requests.exceptions.RequestException as e:
            messagebox.showerror("错误", f"{name}下载地址连接失败: {str(e)}")

    def on_email_change(self, event):
        """实时验证邮箱格式"""
        email = self.git_email.get().strip()
        if not email:
            self.email_validate_label.config(text="请输入邮箱", foreground="gray")
            return

        if '@' not in email:
            self.email_validate_label.config(text="缺少@符号", foreground="red")
            return

        is_valid, message = self.validate_email(email)
        if is_valid:
            self.email_validate_label.config(text="✓ 格式正确", foreground="green")
        else:
            self.email_validate_label.config(text=message, foreground="red")

    def on_closing(self):
        """处理窗口关闭事件"""
        if self.active_threads:
            active_tasks = [name for _, name in self.active_threads if self._is_thread_active(_[0])]
            if active_tasks:
                if messagebox.askokcancel("警告",
                    f"以下任务正在进行中:\n{chr(10).join(active_tasks)}\n确定要退出吗？"):
                    self._cleanup()
                    self.root.destroy()
            else:
                self.root.destroy()
        else:
            self.root.destroy()

    def _cleanup(self):
        """清理任务"""
        for thread, name in self.active_threads:
            if self._is_thread_active(thread):
                print(f"等待{name}任务结束...")
                thread.join(timeout=1.0)  # 等待任务结束，最多等待1秒

    def _is_thread_active(self, thread):
        """检查线程是否活动"""
        return thread.is_alive()

    def run(self):
        self.root.mainloop()

    def browse_download_path(self):
        """选择通用下载路径"""
        path = filedialog.askdirectory(title="选择下载位置")
        if path:
            self.download_path.delete(0, tk.END)
            self.download_path.insert(0, path.replace('/', '\\'))
            self.download_dir = path  # 更新下载目录

    def _on_version_selected(self, event=None):
        """VSCode版本选择后更新下载链接"""
        version = self.vscode_version_var.get()
        if version:
            commit = self.vscode_commits.get(version, '')
            if commit:
                url = (f"https://vscode.download.prss.microsoft.com/dbazure/download/stable/"
                      f"{commit}/VSCodeUserSetup-x64-{version}.exe")
            else:
                url = f"https://update.code.visualstudio.com/{version}/win32-x64/stable"
                
            self.vscode_link_entry.configure(state='normal')
            self.vscode_link_entry.delete(0, tk.END)
            self.vscode_link_entry.insert(0, url)
            self.vscode_link_entry.configure(state='readonly')

    def _on_python_version_selected(self, event=None):
        """Python版本选择后更新下载链接"""
        version = self.version_var.get()
        if version:
            url = f"https://www.python.org/ftp/python/{version}/python-{version}-amd64.exe"
            self.python_link_entry.configure(state='normal')
            self.python_link_entry.delete(0, tk.END)
            self.python_link_entry.insert(0, url)
            self.python_link_entry.configure(state='readonly')

    def _on_git_version_selected(self, event=None):
        """Git版本选择后更新下载链接"""
        version = self.git_version_var.get()
        if version:
            url = f"https://github.com/git-for-windows/git/releases/download/v{version}/Git-{version}-64-bit.exe"
            self.git_link_entry.configure(state='normal')
            self.git_link_entry.delete(0, tk.END)
            self.git_link_entry.insert(0, url)
            self.git_link_entry.configure(state='readonly')

    def _on_git_mirror_selected(self, event=None):
        """Git镜像源选择后更新下载链接"""
        version = self.git_version_var.get()
        mirror = self.git_mirror_var.get()
        if version and mirror in self.GIT_MIRRORS:
            base_url = self.GIT_MIRRORS[mirror]
            filename = f"Git-{version}-64-bit.exe"
            
            if mirror == "Github官方":
                url = f"{base_url}v{version}/{filename}"
            else:
                url = f"{base_url}{version}/{filename}"
                
            self.git_link_entry.configure(state='normal')
            self.git_link_entry.delete(0, tk.END)
            self.git_link_entry.insert(0, url)
            self.git_link_entry.configure(state='readonly')
            
            # 更新当前选中的镜像源
            self.current_git_mirror = mirror

    def download_git(self):
        """处理Git下载"""
        version = self.git_version_var.get()
        mirror = self.git_mirror_var.get()
        
        if not version:
            messagebox.showwarning("警告", "请先选择Git版本！")
            return
            
        if mirror not in self.GIT_MIRRORS:
            messagebox.showwarning("警告", "请选择有效的下载源！")
            return

        self.git_download_btn.configure(state='disabled')
        self.install_git_btn.configure(state='disabled')
        thread = threading.Thread(target=self._download_git_thread)
        self._manage_thread(thread, "Git下载")

    def _download_git_thread(self):
        try:
            version = self.git_version_var.get()
            mirror = self.git_mirror_var.get()
            base_url = self.GIT_MIRRORS[mirror]
            filename = f"Git-{version}-64-bit.exe"
            
            if mirror == "Github官方":
                url = f"{base_url}v{version}/{filename}"
            else:
                url = f"{base_url}{version}/{filename}"
            
            response = requests.get(url, stream=True)
            response.raise_for_status()  # 检查下载状态

            # 使用选择的下载路径
            save_path = os.path.join(self.git_download_path.get(), "git-installer.exe")
            
            self._download_file(
                url,
                save_path,
                self.git_download_progress,
                lambda fp: self._on_download_complete('git', fp)
            )

            messagebox.showinfo("成功", f"Git下载完成！\n保存位置：{save_path}")
            
        except Exception as e:
            messagebox.showerror("错误", f"Git下载失败: {str(e)}")
        finally:
            self.git_download_btn.configure(state='normal')
            self.git_download_progress['value'] = 0
            self.active_threads = [(t, n) for t, n in self.active_threads
                                 if t.ident != threading.current_thread().ident]

    def test_repo_connection(self):
        """测试远程仓库连接"""
        repo = self.git_repo.get().strip()
        username = self.repo_username.get().strip()
        password = self.repo_password.get().strip()

        if not all([repo, username, password]):
            messagebox.showwarning("警告", "请填写完整的仓库信息！")
            return

        try:
            # 构建带认证的URL
            repo_url = repo.replace('https://', f'https://{username}:{password}@')
            result = subprocess.run(
                ['git', 'ls-remote', repo_url],
                capture_output=True,
                text=True
            )

            if result.returncode == 0:
                messagebox.showinfo("成功", "仓库连接测试成功！")
            else:
                messagebox.showerror("错误", "仓库连接测试失败，请检查配置！")
        except Exception as e:
            messagebox.showerror("错误", f"连接测试失败: {str(e)}")

    def save_repo_config(self):
        """保存仓库配置"""
        repo = self.git_repo.get().strip()
        username = self.repo_username.get().strip()
        password = self.repo_password.get().strip()
        branch = self.branch_var.get()

        if not all([repo, username, password]):
            messagebox.showwarning("警告", "请填写完整的仓库信息！")
            return

        try:
            # 保存仓库URL
            subprocess.run(['git', 'config', '--global', 'remote.origin.url', repo])

            # 保存默认分支
            subprocess.run(['git', 'config', '--global', 'init.defaultBranch', branch])
            subprocess.run(['git', 'config', '--global', 'branch.master.remote', 'origin'])
            subprocess.run(['git', 'config', '--global', 'branch.master.merge', f'refs/heads/{branch}'])

            # 保存凭证
            subprocess.run(['git', 'config', '--global', 'credential.helper', 'store'])
            with open(os.path.expanduser('~/.git-credentials'), 'w') as f:
                f.write(f'https://{username}:{password}@{repo.replace("https://", "")}')

            messagebox.showinfo("成功", "仓库配置已保存！")
        except Exception as e:
            messagebox.showerror("错误", f"保存配置失败: {str(e)}")

    def browse_git_download_path(self):
        """选择Git下载路径"""
        path = filedialog.askdirectory(title="选择Git下载位置")
        if path:
            self.git_download_path.delete(0, tk.END)
            self.git_download_path.insert(0, path.replace('/', '\\'))
            self.download_dir = path

    def manual_install_vscode(self):
        """手动安装VSCode"""
        filepath = filedialog.askopenfilename(
            title="选择VSCode安装包",
            filetypes=[("EXE files", "*.exe"), ("All files", "*.*")],
            initialdir=self.vscode_download_path.get()
        )
        
        if filepath:
            self.downloaded_files['vscode'] = filepath
            self.install_vscode()

    def manual_install_python(self):
        """手动安装Python"""
        filepath = filedialog.askopenfilename(
            title="选择Python安装包",
            filetypes=[("EXE files", "*.exe"), ("All files", "*.*")],
            initialdir=self.download_path.get()
        )
        
        if filepath:
            self.downloaded_files['python'] = filepath
            self.install_python()

    def manual_install_git(self):
        """手动安装Git"""
        filepath = filedialog.askopenfilename(
            title="选择Git安装包",
            filetypes=[("EXE files", "*.exe"), ("All files", "*.*")],
            initialdir=self.git_download_path.get()
        )
        
        if filepath:
            self.downloaded_files['git'] = filepath
            self.install_git()

    def __del__(self):
        """改进的资源清理"""
        try:
            self._cleanup()
            # 只清理临时下载文件
            for filename in self.downloaded_files.values():
                if filename and os.path.exists(filename) and 'installer' in filename.lower():
                    try:
                        os.remove(filename)
                    except:
                        pass
        except:
            pass

if __name__ == "__main__":
    app = PythonInstaller()
    app.run()
